# coding=utf-8

import ConfigParser
import os.path
import sys
import xml.etree.ElementTree as ET

#为了命令行能够运行:PyCharm在运行时会把当前工程的所有文件夹路径都作为包的搜索路径，而命令行默认只是搜索当前路径。
curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.split(curPath)[0]
sys.path.append(rootPath)

from parse_excel.ClassModel import *
from parse_excel.ItemModel import *
from jinja2 import Environment, PackageLoader

from SourceClassModel import  *
from SourceFieldModel import *
from parse_excel.ServiceModel import *

# 设置编码
reload(sys)
sys.setdefaultencoding('utf-8')

# 读取配置文件
cf = ConfigParser.ConfigParser()
cf.read("config.conf")
ios_model_save_dir = cf.get("save_dir", "ios_models_path")
xml_save_dir = cf.get("save_dir", "xml_save_path")


def parse_xml(xml_name):
    tree = ET.parse(xml_name)
    root = tree.getroot()
    service_model = ServiceModel()
    service_model.name = root.attrib.get('name')
    service_model.service_code = root.attrib.get('code')
    service_model.description = root.attrib.get('description')
    for child in root:
        if child.attrib.get('type') == 'Request':
            class_model = ClassModel()
            class_model.name = child.attrib.get('name')
            class_model.class_type = child.attrib.get('type')
            class_model.version = child.attrib.get('version')
            service_model.request_model = class_model

            for item in child:
                itemModel = get_item_model(item)
                class_model.items.append(itemModel)
        elif child.attrib.get('type') == 'Response':
            class_model = ClassModel()
            class_model.name = child.attrib.get('name')
            class_model.class_type = child.attrib.get('type')
            class_model.version = child.attrib.get('version')
            service_model.response_model = class_model
            for item in child:
                itemModel = get_item_model(item)
                class_model.items.append(itemModel)

    classes = parse_service_model_to_class_models(service_model)
    print '############## 服务%s生成model的个数:%s ##############' %(service_model.service_code, str(len(classes)))
    generate_ios_files(classes)


def get_item_model(node):
    item_model = ItemModel()
    item_model.index = node.attrib.get('index')
    item_model.name = node.attrib.get('name')
    item_model.short_name = node.attrib.get('short_name')
    item_model.item_type = node.attrib.get('type')
    item_model.metadata = node.attrib.get('metadata')
    item_model.length = node.attrib.get('length')
    item_model.required = node.attrib.get('require')
    item_model.range_value = node.attrib.get('range_value')
    item_model.version = node.attrib.get('version')
    item_model.remark = node.attrib.get('description')
    if item_model.is_model():
        for child in node:
            sub_item_model = get_item_model(child)
            item_model.items.append(sub_item_model)
    return item_model


def parse_service_model_to_class_models(service_model):

    classes = []
    if service_model.request_model:
        req_models = generate_service_models(service_model, service_model.request_model)
        classes.extend(req_models)
    if service_model.response_model:
        response_models = generate_service_models(service_model, service_model.response_model)
        classes.extend(response_models)
    return classes


def generate_service_models(service_model, model):
    classes=[]
    class_model_h = SourceClassModel()
    class_model_h.file_name = model.name+'.h'
    class_model_h.class_name = model.name
    class_model_h.service_code = service_model.service_code
    class_model_h.description = service_model.description
    classes_h = generate_class_models(service_model, class_model_h)
    classes.extend(classes_h)

    class_model_m = SourceClassModel()
    class_model_m.file_name = model.name + '.m'
    class_model_m.class_name = model.name
    class_model_m.service_code = service_model.service_code
    class_model_m.description = service_model.description
    classes_m = generate_class_models(service_model, class_model_m)
    classes.extend(classes_m)

    return classes


def generate_class_models(service_model, class_model):
    items = []
    classes = []
    field_list = []
    if class_model.class_name.endswith('Request'):
        items = service_model.request_model.items
    elif class_model.class_name.endswith('Response'):
        items = service_model.response_model.items

    for item in items:
        ios_field_model = SourceFieldModel()
        set_field_model(class_model, ios_field_model, item)
        set_field_annotation(ios_field_model, item)
        if item.is_model() and item.is_busic_model():
            #递归调用
            recurse_generate_class_models(service_model, classes, item, class_model)
        field_list.append(ios_field_model)
    class_model.field_list = field_list
    classes.append(class_model)
    return classes


def recurse_generate_class_models(service_model, class_list, item_model, class_model):
    filed_list = []
    class_source_model = SourceClassModel()
    if class_model.file_name.endswith('.h'):
        class_source_model.file_name = item_model.item_type + 'Model.h'
    elif class_model.file_name.endswith('.m'):
        class_source_model.file_name = item_model.item_type + 'Model.m'

    class_source_model.class_name = item_model.item_type + 'Model'
    class_source_model.service_code = service_model.service_code
    class_source_model.description = item_model.remark

    for item in item_model.items:
        ios_field = SourceFieldModel()
        set_field_model(class_source_model, ios_field, item)
        set_field_annotation(ios_field, item)
        if item.is_model() and item.is_busic_model():
            recurse_generate_class_models(service_model, class_list, item, class_source_model)
        filed_list.append(ios_field)
    class_source_model.field_list = filed_list
    class_list.append(class_source_model)


def set_field_model(class_model, ios_field_model, item_model):
    ios_field_model.field_name = item_model.name
    ios_field_model.field_description = '//'+item_model.remark
    if item_model.metadata == 'List':
        class_model.hasListProperty = True
        ios_field_model.field_type = 'NSMutableArray*'
        ios_field_model.default_value = '[[NSMutableArray alloc] init]'
        ios_field_model.property_type = 'strong'
        ios_field_model.field_parm_type = item_model.item_type + 'Model'
        ios_field_model.parser_type = 'List'
        ios_field_model.field_description = '//' + item_model.remark + ios_field_model.field_parm_type
        if item_model.name.endswith('List'):
            ios_field_model.field_name = item_model.name
        else:
            ios_field_model.field_name = item_model.name + 'List'
        class_model.import_class_list.append("#import \"" + item_model.item_type + "Model.h\"")
    elif item_model.metadata == 'NullableClass' or item_model.metadata == 'Class':
        ios_field_model.field_type = item_model.item_type + 'Model*'
        ios_field_model.default_value = '[[' + item_model.item_type + 'Model alloc] init]'
        ios_field_model.property_type = 'strong'
        ios_field_model.parser_type = item_model.item_type + 'Model'
        ios_field_model.field_name = item_model.name + 'Model'
        class_model.at_class_list.append('@class ' + item_model.item_type + 'Model;')
        class_model.import_class_list.append("#import \"" + item_model.item_type + "Model.h\"")
    elif item_model.metadata == 'Boolean':
        ios_field_model.field_type = 'BOOL'
        ios_field_model.default_value = 'NO'
        ios_field_model.property_type = 'assign'
        ios_field_model.parser_type = 'BOOL'
    elif item_model.metadata == 'Int4' or item_model.metadata == 'Int10':
        ios_field_model.field_type = 'int'
        ios_field_model.default_value = '0'
        ios_field_model.property_type = 'assign'
        ios_field_model.parser_type = 'int'
    elif item_model.metadata == 'Int20':
        ios_field_model.field_type = 'long long'
        ios_field_model.default_value = '0'
        ios_field_model.property_type = 'assign'
        ios_field_model.parser_type = 'long long'
    else:
        ios_field_model.field_type = 'NSString*'
        ios_field_model.default_value = '@\"\"'
        ios_field_model.property_type = 'copy'
        ios_field_model.parser_type = 'NSString'
    ios_field_model.field_description = ios_field_model.field_description + item_model.range_value


def set_field_annotation(ios_field_model, item_model):
    ios_field_model.index = item_model.index
    ios_field_model.require = item_model.required
    ios_field_model.serialize_type = item_model.metadata
    ios_field_model.server_type = item_model.item_type
    ios_field_model.format = item_model.range_value
    ios_field_model.length = 0


def generate_ios_files(classes):
    for class_model in classes:
        template = 'ios_model_h.html'
        if class_model.file_name.endswith('.m'):
            template = 'ios_model_m.html'
        write_data(class_model, template)


def write_data(model, template_name):
    env = Environment(loader=PackageLoader('ParseXML', '../templates'))
    template = env.get_template(template_name)
    file_data = template.render(ClassSourceModel=model)
    models_save_dir = ios_model_save_dir
    if model.file_name.endswith('Model.h') or model.file_name.endswith('Model.m'):
        models_save_dir = ios_model_save_dir+'Model/'

    if not os.path.exists(models_save_dir):
        os.makedirs(models_save_dir)
    with open(models_save_dir+model.file_name, 'w') as f:
        print '正在生成Model文件:' + model.file_name
        f.write(file_data)


if __name__ == '__main__':
    for parent, dir_names, file_names in os.walk(xml_save_dir):
        for filename in file_names:
            parse_xml(os.path.join(parent,filename))
